home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1999 November / Macworld (1999-11).dmg / Shareware World / Comms & Internet / DXF to VRML97 1.0.1 / src / DropUNIX Lib / Lib Sources / DSUserProcs.c < prev    next >
Text File  |  1999-08-26  |  24KB  |  789 lines

  1. /******************************************************************************
  2. **
  3. **  Project Name:    DropShell
  4. **     File Name:    DSUserProcs.c
  5. **
  6. **   Description:    Specific AppleEvent handlers used by the DropBox
  7. **
  8. *******************************************************************************
  9. **                       A U T H O R   I D E N T I T Y
  10. *******************************************************************************
  11. **
  12. **    Initials    Name
  13. **    --------    -----------------------------------------------
  14. **    LDR            Leonard Rosenthol
  15. **    MTC            Marshall Clow
  16. **    SCS            Stephan Somogyi
  17. **    ZSS/RWD        Zen Spider Software/Ryan Davis
  18. **
  19. *******************************************************************************
  20. **                      R E V I S I O N   H I S T O R Y
  21. *******************************************************************************
  22. **
  23. **      Date        Time    Author    Description
  24. **    --------    -----    ------    ---------------------------------------------
  25. **    06/23/94            LDR        Added support for ProcessItem and ProcessFolder handling
  26. **    02/20/94            LDR        Modified Preflight & Postflight to take item count
  27. **    01/25/92            LDR        Removed the use of const on the userDataHandle
  28. **    12/09/91            LDR        Added the new SelectFile userProc
  29. **                                Added the new Install & DisposeUserGlobals procs
  30. **                                Modified PostFlight to only autoquit on odoc, not pdoc
  31. **    11/24/91            LDR        Added the userProcs for pdoc handler
  32. **                                Cleaned up the placement of braces
  33. **                                Added the passing of a userDataHandle
  34. **    10/29/91            SCS        Changes for THINK C 5
  35. **    10/28/91            LDR        Officially renamed DropShell (from QuickShell)
  36. **                                Added a bunch of comments for clarification
  37. **    10/06/91    00:02    MTC        Converted to MPW C
  38. **    04/09/91    00:02    LDR        Added to Projector
  39. **
  40. ******************************************************************************/
  41.  
  42. /******************************************************************************
  43. **
  44. **    DropUnix history:    KRB = Kevin R. Boyce, RWD = Ryan Davis
  45. **
  46. **    04/11/95        RWD        First release.
  47. **    04/21/95        KRB        Added conditional compilation for Think C (Universal headers,
  48. **                             but old ANSI/console library).
  49. **    02/15/96        RWD        Updated for CW8 & added interface changes for better
  50. **                            integration to SIOUX
  51. **
  52. ********************************************************************************/
  53.  
  54. #include "zssdebug.h"
  55.  
  56. #include <Files.h>
  57. #include <StandardFile.h>
  58.  
  59. #if !OLDROUTINELOCATIONS
  60.     #include <Processes.h>
  61.     #include <TextUtils.h>
  62. #else
  63.     #include <SegLoad.h>
  64.     #include <Strings.h>
  65. #endif
  66.  
  67. #include <stdlib.h>            /* For malloc & free */
  68. #include <string.h>            /* For strcpy */
  69. #include <stdio.h>
  70.  
  71. #ifdef __MWERKS__
  72. #include <SIOUX.h>            /* To manipulate the console */
  73. #endif
  74.  
  75. #ifdef THINK_C
  76.     #include <pascal.h>
  77.     extern WindowPtr    gSplashScreen;        /* Needed for unhiliting THINK C console --KRB */
  78. #endif
  79.  
  80. #include "DSGlobals.h"
  81. #include "DSUserProcs.h"
  82.  
  83. #define ValidatePtr(ptr) \
  84.     if (!ptr) {\
  85.         printf("Error allocating memory! Error #%d\n", MemError() );\
  86.         exit(-1);\
  87.     }
  88.  
  89. /* User Structs */
  90.     typedef struct {
  91.         unsigned int count;
  92.         unsigned int max_count;        /* MRM */
  93.         Handle nameListHdl;            /* MRM */
  94.         char ** names;
  95.     } fileNameList, *fileNamePtr, **fileNameHandle;
  96.     
  97. /* Constants for User Structs */
  98. # define MAX_PATH_LEN    1024    /* MRM used in ProcessItem()    */
  99. # define NAME_LIST_BLK    8        /* MRM used in insertFileName()    */
  100.  
  101. /* Static Prototypes */
  102.     static OSErr ProcessFolder(FSSpecPtr myFSSPtr, Handle userDataHandle);
  103.     static OSErr ProcessItem(FSSpecPtr myFSSPtr, Handle userDataHandle);
  104.     static void SetApplicationName(Handle userDataHandle);
  105.     static void AllocateAppNames(Handle *userDataHandle, unsigned long numOfFiles);
  106.     static void DeallocateAppNames(Handle userDataHandle);
  107.     
  108. /* MRM: prototypes for new functions */
  109.     static void insertFileName(char *path, fileNamePtr fileNames, unsigned long len);
  110.     static void initFileNameList(fileNamePtr flp);
  111.     static int enlargeFileNameList(fileNamePtr flp, unsigned long slots_to_add);
  112. /* end of new prototypes */
  113.  
  114. /*
  115.     This routine is called during init time.
  116.     
  117.     It allows you to install more AEVT Handlers beyond the standard four
  118. */
  119.  
  120. pascal void InstallOtherEvents (void) {
  121. }
  122.  
  123.  
  124. /*    
  125.     This routine is called when an OAPP event is received.
  126.     
  127.     Currently, all it does is set the gOApped flag, so you know that
  128.     you were called initally with no docs, and therefore you shouldn't 
  129.     quit when done processing any following odocs.
  130. */
  131.  
  132. pascal void OpenApp (void) {
  133.     gOApped = true;
  134. }
  135.  
  136.  
  137. /*    
  138.     This routine is called when an QUIT event is received.
  139.     
  140.     We simply set the global done flag so that the main event loop can
  141.     gracefully exit.  We DO NOT call ExitToShell for two reasons:
  142.     1) It is a pretty ugly thing to do, but more importantly
  143.     2) The Apple event manager will get REAL upset!
  144. */
  145.  
  146. pascal void QuitApp (void) {
  147.     gDone = true;    /*    All Done! */
  148. }
  149.  
  150.  
  151. /*    
  152.     This routine is the first one called when an ODOC or PDOC event is received.
  153.     
  154.     In this routine you would place code used to setup structures, etc. 
  155.     which would be used in a 'for all docs' situation (like "Archive all
  156.     dropped files")
  157.  
  158.     Obviously, the opening boolean tells you whether you should be opening
  159.     or printing these files based on the type of event recieved.
  160.     
  161.     NEW IN 2.0!
  162.     The itemCount parameter is simply the number of items that were dropped on
  163.     the application and that you will be processing.  This gives you the ability
  164.     to do a single preflight for memory allocation needs, rather than doing it
  165.     once for each item as in previous versions.
  166.     
  167.     userDataHandle is a handle that you can create & use to store your own
  168.     data structs.  This dataHandle will be passed around to the other 
  169.     odoc/pdoc routines so that you can get at your data without using
  170.     globals - just like the new StandardFile.  
  171.     
  172.     We also return a boolean to tell the caller if you support this type
  173.     of event.  By default, our dropboxes don't support the pdoc, so when
  174.     opening is FALSE, we return FALSE to let the caller send back the
  175.     proper error code to the AEManager.
  176. */
  177.  
  178. pascal Boolean PreFlightDocs (Boolean opening, short itemCount, Handle *userDataHandlePtr) {
  179.  
  180.  
  181.     if ((opening) && (itemCount > 0)) {    /* Don't support printing, so don't waste our time */
  182.  
  183.         AllocateAppNames(userDataHandlePtr, itemCount);
  184.         SetApplicationName(*userDataHandlePtr);
  185.     }
  186.  
  187.     return opening;        // we support opening, but not printing - see above
  188. }
  189.  
  190. /*    
  191.     This routine is called for each file passed in the ODOC event.
  192.     
  193.     In this routine you would place code for processing each file/folder/disk that
  194.     was dropped on top of you.
  195. */
  196.  
  197. pascal void OpenDoc ( FSSpecPtr myFSSPtr, Boolean /* opening */, Handle userDataHandle ) {
  198.  
  199.     OSErr    err = noErr;
  200.     
  201.     #if defined(qWalkFolders) && qWalkFolders
  202.         /*
  203.             For this case we need to determine if the FSSpec is a file or folder.
  204.             If it's a folder, we then need to process each item in that folder,
  205.             otherwise just process the item.
  206.         */
  207.         if (FSpIsFolder(myFSSPtr))
  208.             err = ProcessFolder(myFSSPtr, userDataHandle);
  209.         else
  210.             err = ProcessItem(myFSSPtr, userDataHandle);
  211.     #else
  212.         /*
  213.             For this case we just call ProcessItem on the FSSpec above.
  214.         */
  215.         err = ProcessItem(myFSSPtr, userDataHandle);
  216.     #endif
  217.     
  218.     // you should probably do something if you get back an error ;)
  219. }
  220.  
  221.  
  222. /*    
  223.     This routine is the last routine called as part of an ODOC event.
  224.     
  225.     In this routine you would place code to process any structures, etc. 
  226.     that you setup in the PreflightDocs routine.
  227.  
  228.     NEW IN 2.0!
  229.     The itemCount parameter was the number of items that you processed.
  230.     It is passed here just in case you need it ;)  
  231.     
  232.     If you created a userDataHandle in the PreFlightDocs routines, this is
  233.     the place to dispose of it since the Shell will NOT do it for you!
  234. */
  235.  
  236. pascal void PostFlightDocs ( Boolean opening, short /* itemCount */, Handle userDataHandle ) {
  237.  
  238.     /* int index; */
  239.     int argc;
  240.     char ** argv;
  241.     fileNamePtr fileNames;
  242.     
  243.     extern int Main(int argc, char **argv);
  244.  
  245.     #ifdef __MWERKS__
  246.     ClearMenuBar();        /* 1.2 ZSS - if we use SIOUX, we clear the menubar and let it take over... */
  247.     #endif                /* __MWERKS__ */    
  248.     /*
  249.     ** OK, this is IT! We have finally processed all the files, now we send the
  250.     ** pathnames & count off to the REAL unix function...
  251.     */
  252.     HLock(userDataHandle);
  253.         fileNames = *((fileNameHandle) userDataHandle);
  254.         argc = fileNames->count;
  255.         argv = fileNames->names;
  256.  
  257.         (void) Main(argc, argv);
  258.     HUnlock(userDataHandle);
  259.     /*
  260.     ** Now deallocate the memory stored by PreFlightDocs
  261.     */
  262.     
  263.     DeallocateAppNames(userDataHandle);
  264.     
  265.     /*
  266.     ** Reset the globals, this is in case the user invoked us by the menuitem,
  267.     ** the user _could_ run through again if wanted...
  268.     */
  269.     
  270.     #ifdef THINK_C
  271.     /*
  272.     ** Unhilite the stupid THINK C console, so we get keypresses.
  273.     ** This may not be necessary if you have an up-to-date (8.0 or
  274.     ** paid-for 7.0) ANSI/console library.  Or it might, who knows?
  275.     */
  276.     SelectWindow( gSplashScreen );
  277.     #endif
  278.  
  279.     if ( (opening) && (!gOApped) )
  280.         gDone = true;    //    close everything up!
  281.  
  282.     /*
  283.         The reason we do not auto quit is based on a recommendation in the
  284.         Apple event Registry which specifically states that you should NOT
  285.         quit on a 'pdoc' as the Finder will send you a 'quit' when it is 
  286.         ready for you to do so.
  287.     */
  288. }
  289.  
  290. /*
  291.     This routine gets called for any folder (or disk) that the caller wants 
  292.     processed as a set of component items, instead of as a single entity.
  293.     The determining factor is the definition of the qWalkFolders compiler directive.
  294. */
  295. static OSErr ProcessFolder(FSSpecPtr myFSSPtr, Handle userDataHandle)
  296. {
  297.     OSErr        err = noErr;
  298.     short        index, oldIndex, localIndex;
  299.     FSSpec        localFSSpec, curFSSpec;
  300.     CInfoPBRec    cipb;
  301.     Str255        fName, vFName;
  302.     long        dirID, origDirID;
  303.     Boolean        foundPosition;
  304.  
  305.      // copy the source locally to avoid recursion problems
  306.      BlockMoveData(myFSSPtr, &localFSSpec, sizeof(FSSpec));
  307.      
  308.     //    get the dirID for THIS folder, not it's parent!
  309.     BlockMoveData(localFSSpec.name, fName, 32);
  310.     
  311.     cipb.hFileInfo.ioCompletion    = 0L;
  312.     cipb.hFileInfo.ioNamePtr    = fName;
  313.     cipb.hFileInfo.ioVRefNum    = localFSSpec.vRefNum;
  314.     cipb.hFileInfo.ioFDirIndex    = 0;    // use the dir & vRefNum;
  315.     cipb.hFileInfo.ioDirID        = localFSSpec.parID;
  316.     err = PBGetCatInfoSync(&cipb);
  317.     
  318.     if (!err) {        
  319.         origDirID = cipb.dirInfo.ioDrDirID; // copy the sucker
  320.         index = 1;
  321.                 
  322.         // index through all contents of this folder
  323.         while (err == noErr) {
  324.             dirID = origDirID;
  325.             localIndex = index;
  326.             fName [0] = 0;
  327.             cipb.hFileInfo.ioCompletion    = 0L;
  328.             cipb.hFileInfo.ioNamePtr    = fName;
  329.             cipb.hFileInfo.ioVRefNum    = localFSSpec.vRefNum;
  330.             cipb.hFileInfo.ioFDirIndex    = localIndex;    // use a real index
  331.             cipb.hFileInfo.ioDirID        = dirID;
  332.             err = PBGetCatInfoSync(&cipb);
  333.  
  334.             if (!err) {
  335.                 BlockMoveData(fName, curFSSpec.name, 32);
  336.                 curFSSpec.vRefNum    = cipb.hFileInfo.ioVRefNum;
  337.                 curFSSpec.parID        = dirID;
  338.             
  339.                 /*    
  340.                     Check to see if this entry is a folder.
  341.                 */
  342.                 if (cipb.hFileInfo.ioFlAttrib & ioDirMask) {
  343.                     err = ProcessFolder(&curFSSpec, userDataHandle);
  344.                  } else {
  345.                     err = ProcessItem(&curFSSpec, userDataHandle);
  346.                 }
  347.             
  348.                 dirID = origDirID;    
  349.                 localIndex = index;    
  350.  
  351.                 /*    
  352.                     Now take into account new files being created
  353.                     in the current directory & messing up our index.
  354.                     See Dev.CD Vol. XI:Tools & Apps (Moof!):Misc Utilities:
  355.                     Disinfectant & Source 2.5.1:Sample:Notes:Scan Alg    
  356.                 */
  357.                 vFName [0] = 0;
  358.                 cipb.hFileInfo.ioCompletion    = 0L;
  359.                 cipb.hFileInfo.ioNamePtr    = vFName;
  360.                 cipb.hFileInfo.ioVRefNum    = localFSSpec.vRefNum;
  361.                 cipb.hFileInfo.ioFDirIndex    = localIndex;    // use a real index
  362.                 cipb.hFileInfo.ioDirID        = dirID;
  363.                 err = PBGetCatInfoSync(&cipb);
  364.                 oldIndex = index;
  365.                 if (!err) {
  366.                     /*    If they're equal - same place, go to next */
  367.                     if (EqualString (vFName, fName, false, false))
  368.                         index++;
  369.                 }
  370.                 
  371.                 /*    If we didn't advance, then perhaps a file was created or deleted */
  372.                 if (oldIndex == index) {
  373.                     oldIndex        = index;    /* save off the old */
  374.                     index            = 0;        /* and start at the beginning */
  375.                     err                = noErr;
  376.                     vFName [0]        = 0;
  377.                     foundPosition    = false;
  378.                     
  379.                     while (!foundPosition) {
  380.                         index++;
  381.                         vFName [0] = 0;
  382.                         cipb.hFileInfo.ioCompletion    = 0L;
  383.                         cipb.hFileInfo.ioNamePtr    = vFName;
  384.                         cipb.hFileInfo.ioVRefNum    = localFSSpec.vRefNum;
  385.                         cipb.hFileInfo.ioFDirIndex    = index;    /* now use a real index */
  386.                         cipb.hFileInfo.ioDirID        = dirID;
  387.                         err = PBGetCatInfoSync(&cipb);
  388.                         
  389.                         if (err == fnfErr) {  // we've just been deleted
  390.                             index = oldIndex;
  391.                             foundPosition = true;
  392.                             err = noErr;    // have to remember to reset this!
  393.                         }
  394.                         
  395.                     /*    found same file & same index position */
  396.                     /*    so try the next item */
  397.                         if ((!foundPosition) && EqualString(fName, vFName, false, false)) {
  398.                             index++;
  399.                             foundPosition = true;
  400.                         }
  401.                     }
  402.                 }
  403.             }
  404.         }
  405.     }
  406.     
  407.     return(err);
  408. }
  409.  
  410. /*
  411.     This routine is called when the user chooses "Select File…" from the
  412.     File Menu.
  413.     
  414.     Currently it simply calls the new StandardGetFile routine to have the
  415.     user select a single file (any type, numTypes = -1) and then calls the
  416.     SendODOCToSelf routine in order to process it.  
  417.             
  418.     The reason we send an odoc to ourselves is two fold: 1) it keeps the code
  419.     cleaner as all file openings go through the same process, and 2) if events
  420.     are ever recordable, the right things happen (this is called Factoring!)
  421.  
  422.     Modification of this routine to only select certain types of files, selection
  423.     of multiple files, and/or handling of folder & disk selection is left 
  424.     as an exercise to the reader.
  425. */
  426. pascal void SelectFile (void)
  427. {
  428.     StandardFileReply    stdReply;
  429.     SFTypeList            theTypeList;
  430.  
  431.     StandardGetFile(NULL, -1, theTypeList, &stdReply);
  432.     if (stdReply.sfGood)    // user did not cancel
  433.         SendODOCToSelf(&stdReply.sfFile);    // so send me an event!
  434. }
  435.  
  436. /*
  437.     This routine is called during the program's initialization and gives you
  438.     a chance to allocate or initialize any of your own globals that your
  439.     dropbox needs.
  440.     
  441.     You return a boolean value which determines if you were successful.
  442.     Returning false will cause DropShell to exit immediately.
  443. */
  444.  
  445. pascal Boolean InitUserGlobals(void)
  446. {
  447.     /* Str255 appName; */
  448.     
  449.     #ifdef __MWERKS__
  450.     SIOUXSettings.initializeTB    = false;
  451.     SIOUXSettings.standalone    = true;
  452.     SIOUXSettings.setupmenus    = true;
  453.     #endif
  454.  
  455.     return(true);    // nothing to do, it we must be successful!
  456. }
  457.  
  458. /*
  459.     This routine is called during the program's cleanup and gives you
  460.     a chance to deallocate any of your own globals that you allocated 
  461.     in the above routine.
  462. */
  463. pascal void DisposeUserGlobals(void)
  464. {
  465. }
  466.  
  467. long GetFullPath (FSSpec *fsspec, char *path, OSErr *err);
  468. unsigned short ReverseCopyP2CStr (unsigned char *pas, char *c);
  469. void ReverseCStr (char *str);
  470.  
  471. /*
  472.     This routine gets called for each item (which could be either a file or a folder)
  473.     that the caller wants dropped.  The determining factor is the definition of the 
  474.     qWalkFolder compiler directive.   Either way, the item in question should be
  475.     processed as a single item and not "dissected" into component units (like subfiles
  476.     of a folder!)
  477. */
  478. OSErr ProcessItem(FSSpecPtr myFSSPtr, Handle userDataHandle)
  479. {
  480.     char    path[MAX_PATH_LEN];
  481.     OSErr    err = noErr;
  482.     unsigned long    len;
  483.     
  484.     len = GetFullPath (myFSSPtr, path, &err);
  485.     
  486.     if( (err == noErr) && (len > 0) ) {
  487.         fileNamePtr fileNames;
  488.         
  489.         HLock(userDataHandle);
  490.             fileNames = *((fileNameHandle) userDataHandle);
  491.             insertFileName( path, fileNames, len ) ;
  492.             err = MemError() ;
  493.         HUnlock(userDataHandle);
  494.     }
  495.  
  496.     return(err);
  497. }
  498.  
  499. long GetFullPath (FSSpec *fsspec, char *path, OSErr *err)
  500. {
  501.     short        volume = fsspec->vRefNum;
  502.     OSErr        fsErr = noErr;
  503.     CInfoPBRec    catinfo;
  504.     char            dirName[64];
  505.     long            retLen = 0L, len;
  506.     register char    *p = path;
  507.     
  508.     // All comments assume a  file whose full path is
  509.     //    HD:Fonts:Garamond
  510.     
  511.     // If fsspec doesn't designate a file (i.e., it's a volume or directory), we write a colon
  512.     if ( FSpIsFolder (fsspec)) {
  513.         *p++ = ':';
  514.         retLen++;
  515.     }
  516.     
  517.     // First, copy the file name backwards from a Pascal to a C string:
  518.     //    "\pGaramond"  becomes "dnomaraG"
  519.  
  520.     len = (long) ReverseCopyP2CStr (fsspec->name, p);
  521.     p += len;
  522.     retLen += len;
  523.     
  524.     /* Yea, I know this is cheap, but it is used ONCE AND it makes it clearer {RWD} */
  525.     
  526.     #define FSpIsVolume(FSSpec) ((FSSpec)->parID == fsRtParID)
  527.     
  528.     if ( ! FSpIsVolume (fsspec)) {        // Don't do anything more if we've got a volume
  529.     
  530.         catinfo.dirInfo.ioVRefNum = volume;
  531.         catinfo.dirInfo.ioNamePtr = (StringPtr) dirName;
  532.         catinfo.dirInfo.ioDrParID = fsspec->parID;
  533.         
  534.         // Now copy the rest of the path, one level at a time, backwards:
  535.         //    "dnomaraG:stnoF:DH"
  536.         do {
  537.             catinfo.dirInfo.ioFDirIndex = -1;
  538.             catinfo.dirInfo.ioDrDirID = catinfo.dirInfo.ioDrParID;    // <= This is the key — go from the
  539.                                                         //    current folder to its parent
  540.             fsErr = PBGetCatInfoSync (&catinfo);
  541.             if (fsErr == noErr) {
  542.                 *p++ = ':';
  543.                 retLen += 1 + (len = ReverseCopyP2CStr ((StringPtr) dirName, p));
  544.                 p += len;
  545.             } else {
  546.                 *err = fsErr;
  547.                 return retLen;
  548.             }
  549.         } while (catinfo.dirInfo.ioDrDirID != fsRtDirID);
  550.     }
  551.     
  552.     // Finally, reverse the string and return its length and any error that might have occurred (ReverseCopyP2CStr has
  553.     //    already appended a null character, so we don't have to worry about it here)
  554.     ReverseCStr (path);
  555.     *err = fsErr;
  556.     return retLen;
  557. }
  558.  
  559. unsigned short ReverseCopyP2CStr (register unsigned char *pas, register char *c)
  560. {
  561.     register short    i, len = *pas++;
  562.     
  563.     for (i = len, c += len; i > 0; i--)
  564.         *--c = *pas++;
  565.     c += len;
  566.     *c = '\0';
  567.     return len;
  568. }
  569.  
  570. void ReverseCStr (register char *str)
  571. {
  572.     register short        n = 0L, i;
  573.     register char        t, *p1, *p2;
  574.     
  575.     p1 = p2 = str;
  576.     while (*p2++)
  577.         ;
  578.     p2--;
  579.     n = (p2 - p1) / 2;
  580.     for (i = n; i > 0; i--) {
  581.         t = *--p2;
  582.         *p2 = *p1;
  583.         *p1++ = t;
  584.     }
  585. }
  586.  
  587. static void SetApplicationName(Handle userDataHandle) {
  588.  
  589.     Str255 appName;
  590.     fileNamePtr fileNames;
  591.     
  592.     if (userDataHandle == NULL || *userDataHandle == NULL) {
  593.         Panic(kMemoryError);
  594.     }
  595.  
  596.     GetMyAppName(appName);
  597.  
  598.     if (appName == NULL) {
  599.         Panic(kMemoryError);
  600.     }    
  601.     
  602.     HLock(userDataHandle);
  603.         fileNames = *((fileNameHandle) userDataHandle);
  604.         if ( fileNames->names[0] == NULL) {
  605.             fileNames->names[0] = (char *) NewPtr((size_t) appName[0] + 1); /* pstr's size in byte 0 */
  606.             if (fileNames->names[0] == NULL || MemError()) {
  607.                 Panic(kMemoryError);
  608.             }
  609.             strcpy(fileNames->names[0], p2cstr(appName));
  610.             fileNames->count++;
  611.         }
  612.     HUnlock(userDataHandle);
  613. }
  614.  
  615. static void AllocateAppNames(Handle *userDataHandle, unsigned long numOfFiles) {
  616.  
  617.     fileNameHandle fileNameHdl;
  618.     fileNamePtr fileNames;
  619.     
  620.     fileNameHdl = (fileNameHandle) NewHandleClear(sizeof(fileNameList));
  621.     if (fileNameHdl == NULL || MemError() ) {
  622.         Panic(kMemoryError);
  623.     }
  624.     
  625.     HLock((Handle) fileNameHdl);
  626.     /************************************************
  627.     *    MRM: set up the array in the fileNameList 
  628.     * structure - make sure to include a slot for
  629.     * the application's name.
  630.     */
  631.         fileNames = *fileNameHdl;
  632.         
  633.         initFileNameList( fileNames );
  634.         if( enlargeFileNameList(fileNames, (numOfFiles + 1)) ) {
  635.             Panic(kMemoryError);
  636.         }
  637.  
  638.     HUnlock((Handle) fileNameHdl);
  639.     
  640.     *userDataHandle = (Handle) fileNameHdl;
  641.     
  642.     if (*userDataHandle == NULL || **userDataHandle == NULL) {
  643.         Panic(kMemoryError);
  644.     }
  645. }
  646.  
  647. /* ______________________________________________________________ 
  648. *
  649. *    I had to add these three functions for use when walking
  650. * folders.  They implement the array of strings fileNames->names 
  651. * as a resizeable, handle-based thing.  I needed this because
  652. * recursion into folders often required me to extend  
  653. * ((FileNameList *) *userDataHandle))->names beyond the size 
  654. * with which it was created when AllocateAppNames() was invoked.
  655. *
  656. *    MRM, 19 Jan, 1998
  657. *
  658. * ______________________________________________________________ */
  659.  
  660. static void insertFileName(char *path, fileNamePtr fileNames, unsigned long len ) 
  661. /*****************************************************************
  662. *    This should only get called when userDataHandle is already
  663. * a sensible object, to add a new file name to the end of the
  664. * list.  If the list is full, this function attempts to enlarge
  665. * it.
  666. */
  667. {
  668.     dassert( fileNames != NULL, "fileNames shall not be passed in NULL");
  669.     dassert( path != NULL, "path shall not be passed in NULL");
  670.             
  671.     if( (fileNames->count < fileNames->max_count) || 
  672.         (enlargeFileNameList( fileNames, NAME_LIST_BLK) == noErr) ) {
  673.     /***************************************************************
  674.     *    All appears to be well . . . these lines come from the
  675.     * original ProcessItem().
  676.     */
  677.         fileNames->names[(fileNames->count)] = (char *) NewPtr((len+1) * sizeof(char));
  678.         ValidatePtr(fileNames->names[(fileNames->count)]);
  679.     
  680.         strcpy(fileNames->names[(fileNames->count)], path);
  681.         (fileNames->count)++;
  682.     }
  683.     else {
  684.     /**************************************************************
  685.     *    We've run out of space for names - die.
  686.     */
  687.         Panic(kMemoryError);
  688.     }
  689. }
  690. /* ______________________________________________________________ */
  691.  
  692. static void initFileNameList( fileNamePtr flp )
  693. /*************************************************
  694. *    Set up an empty file list holding no names
  695. */
  696. {
  697.     dassert( flp != NULL, "flp shall not be passed in NULL");
  698.     
  699.     flp->count = flp->max_count = 0 ;
  700.     flp->nameListHdl = NULL ;
  701.     flp->names = NULL ;
  702. }
  703. /* ______________________________________________________________ */
  704.  
  705. static int enlargeFileNameList( fileNamePtr flp, unsigned long slots_to_add )
  706. /*****************************************************************************
  707. *    Add some more entries to the array of strings that holds the list of 
  708. * names.  Use memError() to set the return value; zero (noErr) for success,
  709. * non-zero for failure.
  710. */
  711. {
  712.     unsigned long    j, new_size ;
  713.     
  714.     dassert( flp != NULL, "flp shall not be passed in NULL");
  715.     dassert( ((flp->max_count > 0) || (flp->names == NULL)), "Either max shall be > 0 or names shall be NULL");
  716.     
  717.     if( slots_to_add  ) {
  718.     /********************************************************
  719.     *    If the list's Handle is NULL, we should allocate a
  720.     * fresh one, otherwise we should unlock and try to
  721.     * enlarge the old one.
  722.     */
  723.         new_size = (flp->max_count + slots_to_add) * sizeof(char *) ;
  724.         if( flp->nameListHdl == NULL ) 
  725.             flp->nameListHdl = NewHandle( new_size ) ;
  726.         else {
  727.         /*****************************************************
  728.         *    Unlock the Handle and resize it.
  729.         */
  730.             HUnlock( flp->nameListHdl ) ;    
  731.             SetHandleSize( (Handle) flp->nameListHdl, new_size ) ;
  732.         }
  733.         
  734.     /**********************************************************
  735.     *    If all has gone well, flp->nameListHndl is now a
  736.     * newer, bigger thing.  If so, re-lock it and dereference
  737.     * it, recording the enlargement in flp->max_count.
  738.     */    
  739.         if( MemError() == noErr ) {
  740.         /******************************************************
  741.         *    Hurrah. Make sure the new slots have NULL 
  742.         * pointers in 'em.
  743.         */
  744.             HLockHi( flp->nameListHdl ) ;
  745.         
  746.             flp->names = (char **) *(flp->nameListHdl) ;
  747.             flp->max_count += slots_to_add ;
  748.             
  749.             for( j = flp->count ; j < flp->max_count ; j++ )
  750.                 flp->names[j] = NULL ;
  751.         }
  752.     }
  753.     
  754.     return( MemError() ) ;
  755. }
  756. /* ____________________________ */
  757. /*    end of MRM's insertions        */
  758. /* ____________________________ */
  759.  
  760. static void DeallocateAppNames(Handle userDataHandle) {
  761.  
  762.     fileNamePtr fileNames;
  763.     unsigned int index;
  764.     
  765.     HLock(userDataHandle);
  766.         fileNames = *((fileNameHandle) userDataHandle);
  767.         if (fileNames == NULL) {
  768.             Panic(kMemoryError);
  769.         }
  770.         for (index = 0; index < fileNames->count; index++) {
  771.             if (fileNames->names[index] != NULL) {
  772.                 DisposePtr(fileNames->names[index]);
  773.                 FailOnError(MemError(), kMemoryError);
  774.                 fileNames->names[index] = NULL;
  775.             }
  776.         }
  777.         DisposeHandle( (Handle) fileNames->nameListHdl ) ;
  778.         if (MemError()) {
  779.             Panic(kMemoryError);
  780.         }
  781.         fileNames = NULL;
  782.     HUnlock(userDataHandle);
  783.     
  784.     DisposeHandle(userDataHandle);
  785.     if (MemError()) {
  786.         Panic(kMemoryError);
  787.     }
  788. }
  789.